package com.lx.boot.db;

import com.lx.boot.OS;
import com.lx.boot.web.valid.Validate;
import com.lx.constant.DefaultBaseConstant;
import com.lx.boot.db.domain.DataBaseProperties;
import com.lx.util.LX;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 动态数据源实现类
 * @author ylx
 * db.host 数据库地址
 * db.name 数据库名称(默认项目名)
 * db.user 数据库用户
 * db.pass 数据库密码
 */
@Slf4j
@Component
@ConditionalOnProperty(name = DefaultBaseConstant.DB_ENABLE, havingValue = "true", matchIfMissing = true)
public class DynamicDataSource extends AbstractRoutingDataSource implements BeanPostProcessor {

    public DynamicDataSource(){
        setTargetDataSources(new HashMap<>());
    }
    /** 用来缓存dataSource*/
    private final static Map<String, DataSource> dataSourceMap = new HashMap<>();
    /**
     * 如果不希望数据源在启动配置时就加载好，可以定制这个方法，从任何你希望的地方读取并返回数据源
     * 比如从数据库、文件、外部接口等读取数据源信息，并最终返回一个DataSource实现类对象即可
     */
    @Override
    protected DataSource determineTargetDataSource() {
        return getDataSource();
    }

    //说明:生成数据源
    /**{ ylx } 2020/8/31 17:10 */
    public DataSource getDataSource() {
        //获取当前线程指定的数据源
        DataBaseProperties dataBaseProperties = OS.getCustomDbInfo();
        return getDataSource(dataBaseProperties);
    }

    //说明:生成数据源
    /**{ ylx } 2020/8/31 17:10 */
    public DataSource getDataSource(DataBaseProperties dataBaseProperties) {
        //获取当前线程指定的数据源
        if (LX.isEmpty(dataBaseProperties)){
            dataBaseProperties = OS.getBeanProperty(DataBaseProperties.class);
        }
        Validate.validate(dataBaseProperties);
        String url = dataBaseProperties.getUrl();
        if (!url.contains("jdbc:")){
            url = "jdbc:mysql://"+url+"?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true";
            dataBaseProperties.setUrl(url);
        }
        //默认数据源
        log.info("切换到数据源:"+url);
        String md5 = LX.md5(dataBaseProperties.getUrl() + dataBaseProperties.getUsername() + dataBaseProperties.getPassword());
        if (dataSourceMap.containsKey(md5)){
            return dataSourceMap.get(md5);
        }
        //创建datasource
        DataSourceBuilder<?> builder = DataSourceBuilder.create();
        DataSourceBuilder<HikariDataSource> dbuilder = builder.type(HikariDataSource.class);
        builder.url(dataBaseProperties.getUrl());
        builder.username(dataBaseProperties.getUsername());
        builder.password(dataBaseProperties.getPassword());
        //解决特殊字符问题
        HikariDataSource dataSource = dbuilder.build();
        dataSource.setConnectionInitSql(dataBaseProperties.getConnectionInitSql());
        dataSourceMap.put(md5,dataSource);
        return dataSource;
    }

    /**
     * 如果希望所有数据源在启动配置时就加载好，这里通过设置数据源Key值来切换数据，定制这个方法
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return null;
    }

}
